home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 January: Mac OS SDK / Dev.CD Jan 00 SDK1.toast / Development Kits / Mac OS / Apple Guide / Engineering / APISample / APISampleCW / Source / UApp.cp < prev    next >
Encoding:
Text File  |  1994-08-23  |  34.0 KB  |  1,302 lines  |  [TEXT/MPS ]

  1. // Copyright ©1994 Apple Computer, Inc.
  2. // Author: John Powers
  3. // Date:   27-Aug-94
  4.  
  5. // UApp.cp
  6. // The derived application class.
  7. // The TApplication and TDocument folders
  8. // have been left unchanged  from the developer CD.
  9. // Our use of the application is tailored in the classes below.
  10.  
  11. #ifndef __UAPP__
  12.     #include "UApp.h"
  13. #endif
  14.  
  15. #if __WantMoGuide__
  16.     #ifndef __UAPPMO__
  17.         #include "UAppMo.h"
  18.     #endif
  19. #endif
  20.  
  21. Boolean gAGuideAvailable;
  22.  
  23.         // Segment
  24.  
  25. #pragma segment Main
  26.  
  27. // =========================================================================
  28. // main
  29. // ---------------------------------------------------------------------
  30. // main
  31. // Application entry point.
  32. // It all starts here.
  33. // If we need it, we can make ourApp global.
  34. int
  35. main()
  36. {
  37. #if __WantMoGuide__
  38.     TAppMo* ourApp = new TAppMo;
  39. #else
  40.     TApp* ourApp = new TApp;
  41. #endif
  42.     if(!ourApp)
  43.     {
  44.         return 0;
  45.     }
  46.             // Do basic initialization, then wait in
  47.             // the event loop for the startup event.
  48.     if(ourApp->Init()==noErr)
  49.     {
  50.         ourApp->EventLoop();
  51.         ourApp->Quit();
  52.     }
  53.     return 0;
  54. }
  55.  
  56. // ------------------------------------------------------------------------
  57. // AlertIfError
  58. // Display an alert if an error code is passed.
  59. // Return the error code.
  60. OSErr
  61. AlertIfError(OSErr err)
  62. {
  63.     if(err!=noErr)
  64.     {
  65.         DialogPtr    pDlog;
  66.         GrafPtr        pOldPort;
  67.         Boolean        isShowing=true;
  68.         GetPort(&pOldPort);
  69.         pDlog = GetNewDialog(kAlertIfErrorDialogID, nil, FRONT_WINDOW);
  70.         if(pDlog)
  71.         {
  72.             Handle    hDItem;
  73.             short    itemType;
  74.             Rect    itemRect;
  75.             Str255    textStr;
  76.                 // Error number
  77.             NumToString(err, textStr);
  78.             GetDItem(pDlog, kAlertIfErrorErrNum, &itemType, &hDItem, &itemRect);
  79.             SetIText(hDItem, textStr);
  80.                 // Show dialog.
  81.             CenterWindow(pDlog);
  82.             SetPort(pDlog);
  83.             ShowWindow(pDlog);
  84.                 // Draw default outline around OK button.
  85.             GetDItem(pDlog, kAlertIfErrorOK, &itemType, &hDItem, &itemRect);
  86.             PenSize(3,3);
  87.             InsetRect(&itemRect, -4, -4);
  88.             FrameRoundRect(&itemRect, 16, 16);
  89.             PenNormal();
  90.                 // Let user read.
  91.             short itemHit;
  92.             while (isShowing) {
  93.                 ModalDialog(nil, &itemHit);
  94.                 isShowing = itemHit!=kAlertIfErrorOK;
  95.                 }
  96.             DisposeDialog(pDlog);
  97.         }
  98.         SetPort(pOldPort);
  99.     }
  100.     return err;
  101. }
  102.  
  103. // ------------------------------------------------------------------------
  104. // CenterWindow
  105. //
  106. void
  107. CenterWindow(WindowPtr pWin)
  108. {
  109.     Point    windowLoc;
  110.     Rect    boundsRect;
  111.     GetWindowBounds(pWin, &boundsRect);
  112.     short windowHeight = pWin->portRect.bottom - pWin->portRect.top;
  113.     short windowWidth = pWin->portRect.right - pWin->portRect.left;
  114.     short boundsHeight = boundsRect.bottom - boundsRect.top;
  115.     short boundsWidth = boundsRect.right - boundsRect.left;
  116.     windowLoc.v = boundsRect.top + ((boundsHeight - windowHeight) / 2);
  117.     windowLoc.h = boundsRect.left + ((boundsWidth - windowWidth) / 2);
  118.     MoveWindow(pWin, windowLoc.h, windowLoc.v, false);
  119. }
  120.  
  121. // ------------------------------------------------------------------------
  122. // GetWindowBounds
  123. // Get the bounds for the window.
  124. // The menubar is excluded from the main device bounds.
  125. // If the window overlaps devices, use the smallest device
  126. // for the window top and bottom bounds.
  127. // 
  128. void
  129. GetWindowBounds(WindowPtr pWin, Rect* pBoundsRect)
  130. {
  131.             // See if we have Color QuickDraw.
  132.     SysEnvRec    sysEnv;
  133.     SysEnvirons( curSysEnvVers, &sysEnv );
  134.     if (!sysEnv.hasColorQD)
  135.         *pBoundsRect = qd.screenBits.bounds;
  136.     else
  137.     {
  138.         typedef union {
  139.             Rect    rect;
  140.             struct {
  141.                 Point    topleft;
  142.                 Point    botright;
  143.             } corner;
  144.         } GlobRect;
  145.         Rect        deviceRect;
  146.         GlobRect    windowRect;
  147.         Rect        overlapRect;
  148.         GDHandle    hGD;
  149.         GDHandle    hGDMain = GetMainDevice();
  150.         GrafPtr        savePort;
  151.                 // Get our window's rectangle in global coordinates.
  152.         windowRect.rect = pWin->portRect;
  153.         GetPort(&savePort);
  154.         SetPort(pWin);
  155.         LocalToGlobal(&windowRect.corner.topleft);
  156.         LocalToGlobal(&windowRect.corner.botright);
  157.                 // Initialize *pBoundsRect.
  158.         *pBoundsRect = (*GetGrayRgn())->rgnBBox;
  159.                 // Loop to examine each device for overlap with our window.
  160.         for (hGD = GetDeviceList(); hGD; hGD = GetNextDevice(hGD))
  161.         {
  162.                     // Look for active screen device.
  163.                 if (TestDeviceAttribute(hGD, screenDevice))
  164.                 {
  165.                     if (TestDeviceAttribute(hGD, screenActive))
  166.                     {
  167.                         deviceRect = (**hGD).gdRect;    // global bounds of device.
  168.                                 // Check for overlap of device and window.
  169.                         if (SectRect(&deviceRect, &windowRect.rect, &overlapRect))
  170.                         {
  171.                                 // We have overlap; if main device, exclude menubar.
  172.                             if(hGD==hGDMain)
  173.                             {
  174.                                 deviceRect.top += GetMBarHeight();
  175.                             } // if(hGD…
  176.                                 // Set top and bottom bounds for window.
  177.                             if(pBoundsRect->top < deviceRect.top)
  178.                                                     pBoundsRect->top = deviceRect.top;
  179.                             if(pBoundsRect->bottom > deviceRect.bottom)
  180.                                                     pBoundsRect->bottom = deviceRect.bottom;
  181.                                                     
  182.                             // clip left and right to left and right side of screens on which
  183.                             // the window resides
  184.                             
  185.                             if ( windowRect.rect.left > deviceRect.left && 
  186.                                     pBoundsRect->left < deviceRect.left )
  187.                                 {
  188.                                 pBoundsRect->left = deviceRect.left;
  189.                                 }
  190.                             if ( windowRect.rect.right < deviceRect.right && 
  191.                                     pBoundsRect->right > deviceRect.right )
  192.                                 {
  193.                                 pBoundsRect->right = deviceRect.right;
  194.                                 }
  195.                                 
  196.                         } // if(SectRect…
  197.                     } // if(TestDeviceAttribute…
  198.                 } // if(TestDeviceAttribute…
  199.         } // for(hGD…
  200.         SetPort(savePort);
  201.     }
  202. };
  203.  
  204. // ------------------------------------------------------------------------
  205. // TApp::HandleAECore
  206. // Handles the core events.
  207. // Comes from the Finder after our application is launched.
  208. // When we are launched, we initialize and then wait for a core event.
  209. // The kAEOpenApplication or kAEOpenDocuments event starts the action!
  210. // The refCon contains our application object.
  211. // Should be in a locked, unpurgeable segment.
  212. //
  213. // Unfortunately, the DTS sample TApplication does not process
  214. // high level events.  We fix that by overriding the EventLoop
  215. // and adding high-level event processing.
  216. //
  217. pascal OSErr
  218. TApp::HandleAECore(AppleEvent& theAppleEvent,
  219.                         AppleEvent& /*theReply*/, long refCon)
  220. {
  221.     OSType        eventId;
  222.     Size        actualSize;
  223.     DescType    returnedType;
  224.     AEKeyword    theAEKeyword;
  225.     OSErr        err=noErr;
  226.     AEDescList    docList;
  227.     long        docCnt;
  228.     FSSpec        fileSpec;
  229.     TApp*        ourApp=(TApp*)refCon;
  230.             // Useless without our application object.
  231.     if(!ourApp)
  232.         return kErrNoAppObject;
  233.             // A core event, get event id.
  234.     err = AEGetAttributePtr(&theAppleEvent, keyEventIDAttr,
  235.                                 typeType, &returnedType,
  236.                                 (Ptr) &eventId, sizeof(eventId),
  237.                                 &actualSize);
  238.     switch (eventId)
  239.     {
  240.         case kAEOpenApplication:
  241.                 // Startup.  Attempt autostart if possible.
  242.             err = ourApp->Start();
  243.             if(err==noErr)
  244.             {
  245.                 if(ourApp->fAutoStart)
  246.                 {
  247.                         // Attempt autostart and get preset database spec.
  248.                     err = ourApp->fAutoStart->AttemptAutoStart();
  249.                     ourApp->fAutoStart->GetFile(ourApp->fPresetGuideFile);
  250.                     if(err!=noErr)
  251.                         ourApp->ExitLoop();
  252.                     else if(gAGuideAvailable)
  253.                     {
  254.                         if(AGGetStatus()==kAGIsActive)
  255.                         {
  256.                                 // Did start Apple Guide with a database.
  257.                                 // Update our database variables.
  258.                             ourApp->fAutoStart->GetRefNum(ourApp->fGuideRefNum);
  259.                         }
  260.                     }
  261.                 }
  262.             }
  263.             break;
  264.         case kAEOpenDocuments:
  265.                 // Ask Apple Guide to open one document.
  266.             err = AEGetParamDesc(&theAppleEvent, keyDirectObject,
  267.                                     typeAEList, &docList);
  268.             if(err==noErr)
  269.             {
  270.                 err = AECountItems(&docList, &docCnt);
  271.                 if(err==noErr && docCnt>0)
  272.                 {
  273.                     err = AEGetNthPtr(&docList, 1, typeFSS, &theAEKeyword,
  274.                                     &returnedType, (Ptr) &fileSpec,
  275.                                     sizeof(fileSpec), &actualSize);
  276.                     if(err==noErr)
  277.                     {
  278.                             err = ourApp->Start();
  279.                             if(err==noErr)
  280.                                 err = ourApp->OpenGuideDatabase(&fileSpec);
  281.                     }
  282.                 }
  283.             }
  284.             break;
  285.         case kAEPrintDocuments:
  286.                 // We're not printing anything.
  287.             break;
  288.         case kAEQuitApplication:
  289.                 // All done.
  290.             ourApp->ExitLoop();
  291.             break;
  292.         case kAEAnswer:
  293.                 // We're not expecting any replies.
  294.             break;
  295.         default:
  296.             break;
  297.     }
  298.     return err;
  299.     
  300. }
  301.  
  302.         // Segment
  303.  
  304. #pragma segment MoG1
  305.  
  306. // =========================================================================
  307. // TApp
  308. // --------------------------------------------------------------------------
  309. // TApp::AdjustMenus
  310. //
  311. void
  312. TApp::AdjustMenus()            // override
  313. {
  314.     MenuHandle    hmFile=GetMHandle(mFile);
  315.     MenuHandle    hmEdit=GetMHandle(mEdit);
  316.             // Always avaliable.
  317.     EnableItem(hmFile, iGetInfo);
  318.     EnableItem(hmFile, iQuit);
  319.     EnableItem(hmEdit, iShowClipboard);
  320.             // Set default case.
  321.     DisableItem(hmFile, iOpenFile);
  322.     DisableItem(hmFile, iCloseFile);
  323.             // If Apple Guide is installed,
  324.             // then we can open a guide database.
  325.     if(gAGuideAvailable)
  326.     {
  327.             // Select and open guide database.
  328.         EnableItem(hmFile, iOpenFile);
  329.             // Check to see if our database is open.
  330.             // If it isn't, then set our refNum to nil.
  331.             // If we track the database in our idle loop,
  332.             // we run the risk of a race condition.
  333.             // For example, MoGuide opens a database and
  334.             // the idle checks to see if it's open.
  335.             // Apple Guide opening may not completed opening
  336.             // the database by the time MoGuide's idle loop is executed.
  337.             // So we check it here, right before we need it.
  338.         if(!AGIsDatabaseOpen(this->fGuideRefNum))
  339.             this->fGuideRefNum = nil;
  340.             // If we have a non-nil this->fGuideRefNum,
  341.             // then our database is open. Permit closing.
  342.         if(this->fGuideRefNum)
  343.             EnableItem(hmFile, iCloseFile);
  344.     }
  345. }
  346.  
  347. // ------------------------------------------------------------------------
  348. // TApp::CloseDoc
  349. //
  350. // Close the document by a "GoAway" on its document.
  351. //
  352. void
  353. TApp::CloseDoc(TDoc* docToClose)
  354. {
  355.     if(docToClose)
  356.     {
  357.             // Update current document and window pointer
  358.             // to that which is to be closed.
  359.         this->fCurDoc = docToClose;
  360.         this->fWhichWindow = this->fCurDoc->GetDocWindow();
  361.         SetPort(this->fWhichWindow);
  362.             // Let the "GoAway" handle it.
  363.         this->DoGoAway();
  364.     }
  365. }
  366.  
  367. // ------------------------------------------------------------------------
  368. // TApp::CopyToClipboard
  369. //
  370. void
  371. TApp::CopyToClipboard()
  372. {
  373.                 // There is no trap equivalent for this operation.
  374. }
  375.  
  376. // ---------------------------------------------------------------------
  377. // TApp::DoAbout
  378. // Display the "About…" box.
  379. void
  380. TApp::DoAbout()
  381. {
  382.     DialogPtr    pDlog;
  383.     Str255        versString;
  384.     short        itemType;
  385.     Handle        hItem;
  386.     Rect        box;
  387.     short        itemHit;
  388.     GrafPtr        savePort;
  389.             // Get dialog.
  390.     pDlog = GetNewDialog(rAboutDlog, kDefaultStorage, (WindowPtr) kInFrontOfAll);
  391.             // Set version informaton.
  392.     GetDItem(pDlog, iAboutTitle, &itemType, &hItem, &box);
  393.     this->GetVersion(versString);
  394.     SetIText(hItem, versString);
  395.             // Add default outline around OK button.
  396.     ShowWindow(pDlog);
  397.     GetDItem(pDlog, iAboutOk, &itemType, &hItem, &box);
  398.     GetPort(&savePort);
  399.     SetPort(pDlog);
  400.     PenSize(3,3);
  401.     InsetRect(&box, -4, -4);
  402.     FrameRoundRect(&box, 16, 16);
  403.     PenNormal();
  404.     SetPort(savePort);
  405.             // Wait for user action.
  406.     ModalDialog(kNoFilterProc, &itemHit);
  407.             // Clean up.
  408.     DisposDialog(pDlog);
  409.     HiliteMenu(0);
  410. }
  411.  
  412. // ------------------------------------------------------------------------
  413. // TApp::DoDBInfoDialog
  414. void
  415. TApp::DoDBInfoDialog(FSSpec& guideFileSpec)
  416. {
  417.     DialogPtr    pDlog;
  418.     GrafPtr        pOldPort;
  419.     Boolean        isShowing=true;
  420.  
  421.     GetPort(&pOldPort);
  422.     pDlog = GetNewDialog(kDBInfoDialogID, nil, FRONT_WINDOW);
  423.     if(pDlog)
  424.     {
  425.         Handle    hDItem;
  426.         short    itemType;
  427.         Rect    itemRect;
  428.         Str255    textStr;
  429.         OSErr    err;
  430.             // Database type
  431.         AGFileDBType databaseType;
  432.         err = AGFileGetDBType(&guideFileSpec, &databaseType);
  433.         NumToString((long) databaseType, textStr);
  434.         GetDItem(pDlog, kDBInfoType, &itemType, &hDItem, &itemRect);
  435.         SetIText(hDItem, textStr);
  436.             // Menu item name
  437.         err = AGFileGetDBMenuName(&guideFileSpec, textStr);
  438.         if(err==noErr)
  439.         {
  440.             GetDItem(pDlog, kDBInfoMenu, &itemType, &hDItem, &itemRect);
  441.             SetIText(hDItem, textStr);
  442.         }
  443.             // Selector count
  444.         short selectorCnt = AGFileGetSelectorCount(&guideFileSpec);
  445.         NumToString((long) selectorCnt, textStr);
  446.         GetDItem(pDlog, kDBInfoSelectorCnt, &itemType, &hDItem, &itemRect);
  447.         SetIText(hDItem, textStr);
  448.         AGFileSelectorType selector;
  449.         AGFileSelectorValueType value;
  450.             // Selector #1
  451.         selector = 0;
  452.         err = AGFileGetSelector(&guideFileSpec, 1, &selector, &value);
  453.         if(err==noErr && selector)
  454.         {
  455.             NumToString(value, textStr);
  456.             GetDItem(pDlog, kDBInfoSelector1Value, &itemType, &hDItem, &itemRect);
  457.             SetIText(hDItem, textStr);
  458.             textStr[0] = 4;
  459.             BlockMove(&selector, &textStr[1], 4);
  460.         }
  461.         else
  462.         {
  463.             GetIndString(textStr, kDBInfoStrId, kStrNoInfo);
  464.         }
  465.         GetDItem(pDlog, kDBInfoSelector1, &itemType, &hDItem, &itemRect);
  466.         SetIText(hDItem, textStr);
  467.             // Selector #2
  468.         selector = 0;
  469.         err = AGFileGetSelector(&guideFileSpec, 2, &selector, &value);
  470.         if(err==noErr && selector)
  471.         {
  472.             NumToString(value, textStr);
  473.             GetDItem(pDlog, kDBInfoSelector2Value, &itemType, &hDItem, &itemRect);
  474.             SetIText(hDItem, textStr);
  475.             textStr[0] = 4;
  476.             BlockMove(&selector, &textStr[1], 4);
  477.         }
  478.         else
  479.         {
  480.             GetIndString(textStr, kDBInfoStrId, kStrNoInfo);
  481.         }
  482.         GetDItem(pDlog, kDBInfoSelector2, &itemType, &hDItem, &itemRect);
  483.         SetIText(hDItem, textStr);
  484.             // Selector #3
  485.         selector = 0;
  486.         err = AGFileGetSelector(&guideFileSpec, 3, &selector, &value);
  487.         if(err==noErr && selector)
  488.         {
  489.             NumToString(value, textStr);
  490.             GetDItem(pDlog, kDBInfoSelector3Value, &itemType, &hDItem, &itemRect);
  491.             SetIText(hDItem, textStr);
  492.             textStr[0] = 4;
  493.             BlockMove(&selector, &textStr[1], 4);
  494.         }
  495.         else
  496.         {
  497.             GetIndString(textStr, kDBInfoStrId, kStrNoInfo);
  498.         }
  499.         GetDItem(pDlog, kDBInfoSelector3, &itemType, &hDItem, &itemRect);
  500.         SetIText(hDItem, textStr);
  501.             // Mixin?
  502.         Boolean isMixin = AGFileIsMixin(&guideFileSpec);
  503.         GetIndString(textStr, kDBInfoStrId, (isMixin)?kStrYes:kStrNo);
  504.         GetDItem(pDlog, kDBInfoMixin, &itemType, &hDItem, &itemRect);
  505.         SetIText(hDItem, textStr);
  506.             // Version
  507.         AGFileMajorRevType majorRev;
  508.         AGFileMinorRevType minorRev;
  509.         err = AGFileGetDBVersion(&guideFileSpec, &majorRev, &minorRev);
  510.         if(err==noErr)
  511.         {
  512.             Str255    majorRevStr;
  513.             Str255    minorRevStr;
  514.             Str255    dotStr;
  515.             NumToString((long)majorRev, majorRevStr);
  516.             NumToString((long)minorRev, minorRevStr);
  517.             GetIndString(dotStr, kDBInfoStrId, kStrDot);
  518.                 // PLstrcpy(textStr, majorRevStr)
  519.             BlockMoveData(majorRevStr, textStr, majorRevStr[0]+1);
  520.                 // PLstrcat(textStr, dotStr)
  521.             BlockMoveData(&dotStr[1], &textStr[textStr[0]+1], dotStr[0]);
  522.             textStr[0] += dotStr[0];
  523.                 // PLstrcat(textStr, minorRevStr)
  524.             BlockMoveData(&minorRevStr[1], &textStr[textStr[0]+1], minorRevStr[0]);
  525.             textStr[0] += minorRevStr[0];
  526.             GetDItem(pDlog, kDBInfoVersion, &itemType, &hDItem, &itemRect);
  527.             SetIText(hDItem, textStr);
  528.         }
  529.             // Script and Region
  530.         AGFileDBScriptType    script;
  531.         AGFileDBRegionType    region;
  532.         err = AGFileGetDBCountry(&guideFileSpec, &script, ®ion);
  533.         if(err==noErr)
  534.         {
  535.             NumToString((long)script, textStr);
  536.             GetDItem(pDlog, kDBInfoScript, &itemType, &hDItem, &itemRect);
  537.             SetIText(hDItem, textStr);
  538.             NumToString((long)region, textStr);
  539.             GetDItem(pDlog, kDBInfoRegion, &itemType, &hDItem, &itemRect);
  540.             SetIText(hDItem, textStr);
  541.         }
  542.             // Show dialog.
  543.         short    itemHit;
  544.         CenterWindow(pDlog);
  545.         SetPort(pDlog);
  546.         ShowWindow(pDlog);
  547.             // Draw default outline around OK button.
  548.         GetDItem(pDlog, kDBInfoOK, &itemType, &hDItem, &itemRect);
  549.         PenSize(3,3);
  550.         InsetRect(&itemRect, -4, -4);
  551.         FrameRoundRect(&itemRect, 16, 16);
  552.         PenNormal();
  553.             // Let user read.
  554.         while (isShowing) {
  555.             ModalDialog(nil, &itemHit);
  556.             isShowing = itemHit!=kDBInfoOK;
  557.             }
  558.         DisposeDialog(pDlog);
  559.     }
  560.     SetPort(pOldPort);
  561. }
  562.  
  563. // ------------------------------------------------------------------------
  564. // TApp::DoGoAway
  565. //
  566. // This is the close side of TApp::ShowArt, ShowClipboard, ShowFeedback.
  567. //
  568. void
  569. TApp::DoGoAway()
  570. {
  571.             // Clear our local document record if
  572.             // it's object is going away.
  573.     if(this->fCurDoc==this->fDocClip)
  574.     {
  575.         this->fDocClip = nil;
  576.         this->fScrap->SetDoc(nil);
  577.     }
  578.             // Inherit go-away action from TApplication
  579.     TApplication::DoGoAway();
  580. }
  581.  
  582. // ------------------------------------------------------------------------
  583. void
  584. TApp::DoHighLevelEvent()
  585. {
  586.     OSErr err = AEProcessAppleEvent(&this->fTheEvent);
  587. }
  588.  
  589. // ------------------------------------------------------------------------
  590. // TApp::DoIdle
  591. // Do our idle and deferred events.
  592. //
  593. // AutoStart keeps track of whether or not guide was ever provided.
  594. // The fQuitAfterGuide flag automatically terminates this
  595. // application when the guide database closes.
  596. //
  597. void
  598. TApp::DoIdle()
  599. {
  600.         // Check for guide run/quit.
  601.     if(this->fAutoStart)
  602.         if(this->fAutoStart->ShouldWeQuit())
  603.             this->ExitLoop();
  604.         // Update the scrap.
  605.     if(this->fScrap)
  606.         this->fScrap->DoIdle();
  607. }
  608.  
  609. // ------------------------------------------------------------------------
  610. // TApp::DoMenuCommand
  611. // This is called when an item is chosen from the menu bar (after calling
  612. // MenuSelect or MenuKey). It does the right thing for each command.
  613. void
  614. TApp::DoMenuCommand(short menuID, short menuItem)        //  override
  615. {
  616.  
  617.     Str255    daName;
  618.     short    daRefNum;
  619.     FSSpec    fileSpec;
  620.  
  621.     switch (menuID)
  622.     {
  623.         case mApple:
  624.             switch ( menuItem )
  625.             {
  626.                 case iAbout:// bring up alert for About
  627.                     this->DoAbout();
  628.                     break;
  629.                 default:    // all non-About items in this menu are DAs et al 
  630.                     GetItem(GetMHandle(mApple), menuItem, daName);
  631.                     daRefNum = OpenDeskAcc(daName);
  632.                     break;
  633.             } // switch
  634.             break;
  635.         case mFile:
  636.             switch ( menuItem )
  637.             {
  638.                 case iOpenFile:
  639.                         // User selects desired database.
  640.                         // Tell Apple Guide to open it..
  641.                     if(this->SelectFile(fileSpec)==noErr)
  642.                         AlertIfError(this->OpenGuideDatabase(&fileSpec));
  643.                     break;
  644.                 case iCloseFile:
  645.                     AlertIfError(AGClose(&this->fGuideRefNum));
  646.                     break;
  647.                 case iGetInfo:
  648.                     if(this->SelectFile(fileSpec)==noErr)
  649.                         this->DoDBInfoDialog(fileSpec);
  650.                     break;
  651.                 case iQuit:
  652.                     this->ExitLoop();
  653.                     break;
  654.                 default:
  655.                     break;
  656.             } // switch
  657.             break;
  658.         case mEdit:
  659.             switch ( menuItem )
  660.             {
  661.                 case iCopy:
  662.                     this->CopyToClipboard();
  663.                     break;
  664.                 case iShowClipboard:
  665.                     this->ShowClipboard();
  666.                     break;
  667.                 default:
  668.                     break;
  669.             } // switch
  670.             break;
  671.         default:
  672.             break;
  673.     } // switch
  674.             // Turn off menu hilite.
  675.     HiliteMenu(0);
  676. } // DoMenuCommand
  677.  
  678. //-----------------------------------------------------------------------
  679. // TApp::EventLoop
  680. // We override the TApplication::EventLoop to add processing
  681. // of high-level events.  While we're at it, since we're
  682. // System 7 only, we can always call WNE.
  683. //
  684. void
  685. TApp::EventLoop()
  686. {
  687.         Boolean        gotEvent;
  688.         EventRecord    tEvt;
  689.                 // call setup routine
  690.         this->SetUp();
  691.                 // The loop
  692.         while(!this->fDone)
  693.         {
  694.             this->SetDoc();
  695.             gotEvent = WaitNextEvent(everyEvent, &tEvt, SleepVal(), this->fMouseRgn);
  696.             this->fTheEvent = tEvt;
  697.             if(!gotEvent)
  698.                 this->DoIdle();
  699.             else        // A real event
  700.             {
  701.                 this->AdjustCursor();
  702.                 switch (fTheEvent.what)
  703.                 {
  704.                     case mouseDown:
  705.                         this->DoMouseDown();
  706.                         break;
  707.                                             
  708.                     case mouseUp:
  709.                         this->DoMouseUp();
  710.                         break;
  711.                                             
  712.                     case keyDown:
  713.                     case autoKey:
  714.                         this->DoKeyDown();
  715.                         break;
  716.                                             
  717.                     case updateEvt:
  718.                         this->DoUpdateEvt();                
  719.                         break;
  720.                                             
  721.                     case diskEvt:
  722.                         this->DoDiskEvt();
  723.                         break;
  724.                                             
  725.                     case activateEvt:
  726.                         this->DoActivateEvt();
  727.                         break;
  728.                                             
  729.                     case osEvt:
  730.                         this->DoOSEvent();
  731.                         break;
  732.                                             
  733.                     case kHighLevelEvent:
  734.                         this->DoHighLevelEvent();
  735.                         break;
  736.  
  737.                     default:
  738.                         break;
  739.                         
  740.                 } // end switch (fTheEvent.what)
  741.             }
  742.                 // update the cursor shape as needed after the event
  743.             this->AdjustCursor();
  744.         }
  745.             // call cleanup handler
  746.         this->CleanUp();
  747. }
  748.  
  749.  
  750. // ------------------------------------------------------------------------
  751. // TApp::GetVersion
  752. // Get the current version of the application.
  753. // Uses the long version string from 'vers' resource #1.
  754. //
  755. void
  756. TApp::GetVersion(Str255 versStr)
  757. {
  758.     Handle    hRes;
  759.     char    *pRes;
  760.     short    i;
  761.  
  762.     if (hRes = GetResource('vers', 1))
  763.     {
  764.         pRes = *hRes;
  765.         pRes += 7 + pRes[6];        // long version pstring
  766.         for(i=0; i<=pRes[0]; i++)
  767.             versStr[i] = pRes[i];    // copy version pstring
  768.     }
  769. }
  770.  
  771. // ---------------------------------------------------------------------
  772. // TApp::OpenGuideDatabase
  773. // Open a guide database.
  774. // Return noErr if successful.
  775. // Update TApp database variables.
  776. //
  777. OSErr
  778. TApp::OpenGuideDatabase(FSSpec *pFileSpec)
  779. {
  780.     OSErr result=noErr;
  781.     if(gAGuideAvailable)
  782.     {
  783.             // Ask Apple Guide to open database.
  784.         result = AGOpen(pFileSpec, 0, nil, &this->fGuideRefNum);
  785.     }
  786.     return result;
  787. }
  788.  
  789. // ---------------------------------------------------------------------
  790. // TApp::Init
  791. // Do the things that our derived application class requires.
  792. // Basic initialization, before we start.
  793. // We store our application object in the core event handler
  794. // refCon so that the handler can use it.  Avoids making it a global.
  795. // Return noErr if successful.
  796. OSErr
  797. TApp::Init()
  798. {
  799.     OSErr        err;
  800.     SysEnvRec    envRec;
  801.     (void) SysEnvirons(curSysEnvVers, &envRec);
  802.             // System 7 is required
  803.     if(envRec.systemVersion<0x0700)
  804.     {
  805.         this->BigBadError(kUserStrId, kStrNotSevenOh);
  806.     }
  807.             // Our menuBar to use when we Start.
  808.     this->fMenuBarID = rMenuBar;
  809.             // Also clear our variables or we may get a bus error
  810.             // at the first DoIdle (before we get the start event.)
  811.     this->fDocClip = nil;
  812.     this->fScrap = nil;
  813.     this->fAutoStart = nil;
  814.             // Install our core event handler.
  815.             // We put the TApp object in the refCon.
  816.     err = AEInstallEventHandler(kCoreEventClass,
  817.                                 typeWildCard,
  818.                             #ifdef __powerc
  819.                                 NewAEEventHandlerProc(TAppMo::HandleAECore),
  820.                             #else
  821.                                 TApp::HandleAECore,
  822.                             #endif
  823.                                 (long)this,
  824.                                 kIsNotSysHandler);
  825.             // Our custom event handler is installed in the derived class.
  826.             // Starting is done in TApp::HandleAECore.
  827.             // We wait until that happens before proceeding.
  828.     this->fGuideRefNum = nil;
  829.             // Check to see if the Apple Guide traps are available.
  830.     long result=0;
  831.     err = Gestalt(gestaltHelpMgrAttr, &result);
  832.     gAGuideAvailable = (err==noErr && (result & (1 << gestaltAppleGuidePresent)));
  833.             // Auto-Start object.
  834.     this->fAutoStart = new TAStart;
  835.     if(!this->fAutoStart)
  836.     {
  837.         return kErrNoAutoStartObj;
  838.     }
  839.             // Initialize the auto-start object.
  840.     err = this->fAutoStart->Init();
  841.     return err;
  842. }
  843.  
  844. // ------------------------------------------------------------------------
  845. // TApp::Quit
  846. // We're quitting, so delete everything.
  847. // All of this probably goes away in the application heap anyway,
  848. // we're just being compulsively tidy.
  849. //
  850. void
  851. TApp::Quit()
  852. {
  853.     SetCursor(*GetCursor(watchCursor));
  854.             // Close the guide database and make Apple Guide quit.
  855.             // Here's a case where we just do it without
  856.             // any checking to see if a database is open or
  857.             // Apple Guide is running. Nor do we check
  858.             // for errors. The API should be robust enough to
  859.             // handle all the possibilities without causing any problem.
  860.     if(gAGuideAvailable)
  861.     {
  862.         (void) AGClose(&this->fGuideRefNum);
  863.         (void) AGQuit();
  864.     }
  865.             // Remove our scrap object.
  866.     if(this->fScrap)
  867.         delete this->fScrap;
  868.             // Remove our Auto-Start object.
  869.     if(this->fAutoStart)
  870.         delete this->fAutoStart;
  871.             // Remove core event handler.
  872.     (void) AERemoveEventHandler(kCoreEventClass,
  873.                                 typeWildCard,
  874.                                 kHandlerNotRequired,
  875.                                 kIsNotSysHandler);
  876.     SetCursor(&qd.arrow);
  877. }
  878.  
  879. // ------------------------------------------------------------------------
  880. // TApp::SendEventToSelf
  881. // Our mechanism for full-factoring.
  882. //
  883. OSErr
  884. TApp::SendEventToSelf(AEEventID theEvent)
  885. {
  886.     AppleEvent    theMessage;
  887.     AppleEvent    theReply;
  888.     OSErr        err=noErr;
  889.             // Make address to self.
  890.     AEAddressDesc        addrDesc;
  891.     ProcessSerialNumber    psn;
  892.     psn.highLongOfPSN = 0;
  893.     psn.lowLongOfPSN = kCurrentProcess;
  894.     err = AECreateDesc(typeProcessSerialNumber, (Ptr) &psn,
  895.                                           sizeof(psn), &addrDesc);
  896.     if(err==noErr)
  897.     {
  898.             // Create AppleEvent for theMessage
  899.         err = AECreateAppleEvent(kAEClassCustom,
  900.                                 theEvent,
  901.                                 &addrDesc, kAutoGenerateReturnID,
  902.                                 kAnyTransactionID, &theMessage);
  903.         if(err==noErr)
  904.         {
  905.                 // Send message.
  906.             err = AESend(&theMessage, &theReply,
  907.                             kAENoReply, kAEHighPriority,
  908.                             kNoTimeOut, nil, nil);
  909.                 // Clean-up
  910.             (void) AEDisposeDesc(&theMessage);
  911.             (void) AEDisposeDesc(&theReply);
  912.         }
  913.         (void) AEDisposeDesc(&addrDesc);
  914.     }
  915.     return err;
  916. }
  917.  
  918. // ------------------------------------------------------------------------
  919. // TApp::SelectFile
  920. // Ask user for database file.
  921. // Dialog ID=rSelectFileDlog (OpenDLOG.rsrc)
  922. // contains a friendly prompt text line.
  923. // Return noErr if successful.
  924. //
  925. OSErr
  926. TApp::SelectFile(FSSpec& selectedFile)
  927. {
  928.     OSErr err=noErr;
  929.     Point where = {-1,-1};
  930.     StandardFileReply    reply;
  931.         // Display both main and mixin files.
  932.     short numTypes = 2;
  933.     SFTypeList typeList = {kAGFileMain, kAGFileMixin, 0, 0};
  934.             // Use custom dialog if available, otherwise use standard.
  935.     Handle hDlog = GetResource('DLOG', rSelectFileDlog);
  936.     if(hDlog!=nil && ResError()==noErr)
  937.     {
  938.         CustomGetFile(nil, numTypes, typeList, &reply,
  939.                         rSelectFileDlog, where,
  940.                         nil, nil, nil, nil, nil);
  941.     }
  942.     else
  943.     {
  944.         StandardGetFile(nil, numTypes, typeList, &reply);
  945.     }
  946.     if(reply.sfGood)
  947.     {
  948.         selectedFile = reply.sfFile;
  949.     }
  950.     else
  951.     {
  952.         selectedFile.name[0] = 0;
  953.         err = kSelectFileCancel;
  954.     }
  955.     return err;
  956. }
  957.  
  958. // ------------------------------------------------------------------------
  959. // TApp::SetDoc
  960. // Set the current window and document.
  961. //
  962. void
  963. TApp::SetDoc()
  964. {
  965.     this->fWhichWindow = FrontWindow();
  966.     if(this->fWhichWindow==nil)
  967.     {
  968.             // No window, default to the last window on the list.
  969.         //this->fWhichWindow = *(WindowPtr*)WindowList;
  970.         this->fCurDoc = nil;
  971.     }
  972.     else
  973.     {
  974.         this->fCurDoc = this->fDocList->FindDoc(this->fWhichWindow);
  975.         SetPort(this->fWhichWindow);
  976.     }
  977. }
  978.  
  979. // ------------------------------------------------------------------------
  980. // TApp::ShowClipboard
  981. // Opens the clipboard window.
  982. // The document window is closed by the go-away box (TApp::DoGoAway).
  983. //
  984. void
  985. TApp::ShowClipboard()
  986. {
  987.     if(this->fDocClip==nil)
  988.     {
  989.             // Clipboard window is not present.
  990.             // Create a document and window for the clipboard.
  991.         this->fDocClip = new TDocClip(kClipboardWinResID);
  992.         if(this->fDocClip)
  993.         {
  994.             this->fDocList->AddDoc((TDocument*) this->fDocClip);
  995.                 // Set the clipboard document window's collaborator.
  996.             this->fDocClip->SetScrapObj(this->fScrap);
  997.             this->fDocClip->SetApp(this);
  998.                 // Set the document collaborator for the scrap object.
  999.             this->fScrap->SetDoc(this->fDocClip);
  1000.                 // Update current document and window pointer.
  1001.             this->fCurDoc = this->fDocClip;
  1002.             this->fWhichWindow = this->fCurDoc->GetDocWindow();
  1003.             SetPort(this->fWhichWindow);
  1004.         }
  1005.     }
  1006.         // Better show it, or at least bring it to the front.
  1007.     this->fDocClip->Show();
  1008.             // Invalidate window so that it will be updated and drawn.
  1009.     this->fDocClip->Invalidate();
  1010. }
  1011.  
  1012. // ---------------------------------------------------------------------
  1013. // TApp::Start
  1014. // Startup the application.  Comes after the Init.
  1015. // The Init is done in main.  The Start comes with the oapp or odoc event.
  1016. // Return noErr if successful.
  1017. OSErr
  1018. TApp::Start()
  1019. {
  1020.     OSErr    err=noErr;
  1021.     SetCursor(*GetCursor(watchCursor));
  1022.             // Install menus.
  1023.     Handle menuBar = GetNewMBar(this->fMenuBarID);
  1024.     if(!menuBar)
  1025.     {
  1026.         return kErrNoMenuBar;
  1027.     }
  1028.     SetMenuBar(menuBar);        // Copy to current menu list.
  1029.     DisposHandle(menuBar);        // Don't need it anymore.
  1030.             // Add DA names to Apple menu.
  1031.     AddResMenu(GetMHandle(mApple), 'DRVR');
  1032.     DrawMenuBar();
  1033.             // Scrap object
  1034.     this->fScrap = new TScrap;
  1035.     if(!this->fScrap)
  1036.     {
  1037.         return kErrNoScrapObject;
  1038.     }
  1039.     SetCursor(&qd.arrow);
  1040.     return err;
  1041. }
  1042.  
  1043. // =========================================================================
  1044. // TAStart
  1045. // ------------------------------------------------------------------------
  1046. TAStart::TAStart()
  1047. {
  1048.         // Guide collaborator.
  1049.     this->fGuideRefNum = nil;
  1050.         // Clear our flags.
  1051.     this->fGuideHasRun = false;
  1052.     this->fQuitAfterGuide = false;
  1053.         // The preset guide database file
  1054.     this->fPresetGuideFile.vRefNum = 0;
  1055.     this->fPresetGuideFile.parID = 0;
  1056.     this->fPresetGuideFile.name[0] = 0;
  1057. }
  1058.  
  1059. // ---------------------------------------------------------------------
  1060. // TAStart::AttemptAutoStart
  1061. // Start a guide database per the autoStart resource.
  1062. // Return an error code if a self auto-start fails.
  1063. // In all other cases, return noErr.
  1064. // An alert is also given if a self auto-start fails.
  1065. //
  1066. // Given that enough startup information is provided,
  1067. // the "autoStartFlag" flag determines whether or not the
  1068. // auto-start is actually done.
  1069. //
  1070. // The following is always done, auto-start or not:
  1071. //    • The guide file spec (fPresetGuideFile) specified in the autoStart
  1072. //      resource will be saved for future use.
  1073. //    • The fQuitAfterGuide flag will be set to the resource field value.
  1074. //
  1075. AGErr
  1076. TAStart::AttemptAutoStart()
  1077. {
  1078.     AGErr result=noErr;
  1079.     Boolean    okayToStart=false;
  1080.             // Default to this application's folder.
  1081.     this->fPresetGuideFile.vRefNum = -*(short*)LMGetSFSaveDisk();
  1082.     this->fPresetGuideFile.parID = *(long*)LMGetCurDirStore();
  1083.     this->fPresetGuideFile.name[0] = 0;
  1084.             // AutoStart resource?
  1085.     Handle hSpecRes = GetIndResource(kResAutoStart, 1);
  1086.     if(hSpecRes)
  1087.     {
  1088.             // We have an autoStart resource, get contents.
  1089.         HLock(hSpecRes);
  1090.         StartSpecPtr pStartSpec = (StartSpecPtr) *hSpecRes;
  1091.             // Set the quit-after-guide flag.
  1092.         this->fQuitAfterGuide = pStartSpec->quitAfterGuide;
  1093.             // Check for auto-start of self.
  1094.         if(pStartSpec->autoStartFlag==kAutoSelf)
  1095.         {
  1096.                 // Auto-start self, get file spec for self.
  1097.             ProcessSerialNumber psn;
  1098.             OSErr err = GetCurrentProcess(&psn);
  1099.             if(err==noErr)
  1100.             {
  1101.                 FSSpec            appFile;
  1102.                 ProcessInfoRec    processInfo;
  1103.                 processInfo.processInfoLength = sizeof(ProcessInfoRec);
  1104.                 processInfo.processName = nil;
  1105.                 processInfo.processAppSpec = &appFile;
  1106.                 err = GetProcessInformation(&psn, &processInfo);
  1107.                 if(err==noErr)
  1108.                 {
  1109.                     this->fPresetGuideFile = appFile;
  1110.                     okayToStart = pStartSpec->autoStartFlag;
  1111.                 }
  1112.             }
  1113.         }
  1114.         else
  1115.         {
  1116.                 // Not a auto-start of self, get file name from resource.
  1117.             if(pStartSpec->fileName[0]>0)
  1118.             {
  1119.                     // We have a file name, that has first priority.
  1120.                 
  1121.                     // PLstrcpy(this->fPresetGuideFile.name, pStartSpec->fileName)
  1122.                 BlockMoveData(pStartSpec->fileName, this->fPresetGuideFile.name, pStartSpec->fileName[0]+1);
  1123.                     // If autoStartFlag flag is set, do auto-start.
  1124.                 okayToStart = pStartSpec->autoStartFlag;
  1125.             }
  1126.             else if(pStartSpec->type>0)
  1127.             {
  1128.                     // Else, we have a guide file type, find a file of that type.
  1129.                 {
  1130.                     short    vRefNum = (-*(short*)LMGetSFSaveDisk());
  1131.                     long    dirID = (*(long*)LMGetCurDirStore());
  1132.                     Boolean    wantMixin = false;
  1133.                     short    dbIndex = 1;
  1134.                     if(AGFileGetIndDB(vRefNum, dirID,
  1135.                                         pStartSpec->type, wantMixin,
  1136.                                         dbIndex, &this->fPresetGuideFile)==noErr)
  1137.                     {
  1138.                             // Found a file of that type, start it.
  1139.                             // If autoStartFlag flag is set, do auto-start.
  1140.                         okayToStart = pStartSpec->autoStartFlag;
  1141.                     }
  1142.                 }
  1143.             }
  1144.         }
  1145.         HUnlock(hSpecRes);
  1146.             // We've setup fPresetGuideFile, let's see if it's okay to start.
  1147.             // No autostart if option key is down.
  1148.         union
  1149.         {
  1150.             KeyMap asMap;
  1151.             Byte asBytes[16];
  1152.         };
  1153.         GetKeys(asMap);
  1154.         Boolean optionKeyNotDown = !(asBytes[0x3A>>3]&(1<<(0x3A&0x07))?true:false);
  1155.         if(okayToStart && optionKeyNotDown)
  1156.         {
  1157.             if(!gAGuideAvailable)
  1158.                 Alert(rAutoStartNeedAlrt, nil);    // Need Apple Guide
  1159.             else
  1160.             {
  1161.                     // Apple Guide is available and we want an auto-start.
  1162.                     // Use topic ID if present, otherwise do general guide startup.
  1163.                 if(pStartSpec->sequenceID)
  1164.                     result = AGOpenWithSequence(&this->fPresetGuideFile,
  1165.                                                  0, nil,
  1166.                                                 pStartSpec->sequenceID,
  1167.                                                 &this->fGuideRefNum);
  1168.                 else
  1169.                     result = AGOpen(&this->fPresetGuideFile,
  1170.                                         0, nil, 
  1171.                                         &this->fGuideRefNum);
  1172.                     // If a self auto-start failed, then we can't go any further.
  1173.                     // Put up an alert.
  1174.                 if(okayToStart==kAutoSelf)
  1175.                 {
  1176.                     if(result!=noErr || AGGetStatus()!=kAGIsActive)
  1177.                     {
  1178.                             // Give the all-purpose "beats me" auto-start alert.
  1179.                             Alert(rAutoStartUnknownAlrt, nil);
  1180.                     }
  1181.                 } // if(okayToStart…
  1182.             } // else if(optionKeyNotDown…
  1183.         } // if(okayToStart…
  1184.     }
  1185.     return result;
  1186. }
  1187.  
  1188. // ------------------------------------------------------------------------
  1189. // TAStart::Init
  1190. // Initialize the TAStart object.
  1191. // Return noErr if successful.
  1192. //
  1193. OSErr
  1194. TAStart::Init()
  1195. {
  1196.     return noErr;
  1197. }
  1198.  
  1199. // ------------------------------------------------------------------------
  1200. // TAStart::ShouldWeQuit
  1201. // Return true if we should quit.
  1202. // We quit if guide has run
  1203. // AND it isn't running now
  1204. // AND fQuitAfterGuide is true.
  1205. //
  1206. Boolean
  1207. TAStart::ShouldWeQuit()
  1208. {
  1209.     Boolean result=false;
  1210.         // Check for guide run/quit.
  1211.     if(gAGuideAvailable)
  1212.     {
  1213.         if(AGGetStatus()==kAGIsSleeping || AGGetStatus()==kAGIsActive)
  1214.             this->fGuideHasRun = true;
  1215.         else
  1216.             result = (this->fGuideHasRun && this->fQuitAfterGuide);
  1217.     }
  1218.     return result;
  1219. }
  1220.  
  1221. // =========================================================================
  1222. // TScrap
  1223. // ------------------------------------------------------------------------
  1224. TScrap::TScrap()
  1225. {
  1226.     this->fLastScrapCount = 0;
  1227.         // Initialize our value for the scrap count.
  1228.     (void) this->Update();
  1229. }
  1230.  
  1231. // ------------------------------------------------------------------------
  1232. // TScrap::DoIdle
  1233. // Do any action required during the idle processing.
  1234. //
  1235. void
  1236. TScrap::DoIdle()
  1237. {
  1238.         // If the scrap is updated and the clipboard window
  1239.         // is showing, update/invalidate the clipboard window.
  1240.     if(this->Update())
  1241.         if(this->fDocClip)
  1242.             this->fDocClip->Invalidate();
  1243. }
  1244.  
  1245. // ------------------------------------------------------------------------
  1246. // TScrap::Draw
  1247. void
  1248. TScrap::Draw(WindowPtr pWin)
  1249. {
  1250.     SetPort(pWin);
  1251.     TextFont(monaco);
  1252.     TextSize(9);
  1253.     long offset;
  1254.     long scrapLen = GetScrap(nil, 'TEXT', &offset);
  1255.     if(scrapLen>0)
  1256.     {
  1257.         Handle hContent = NewHandle(scrapLen);
  1258.         if(hContent)
  1259.         {
  1260.             scrapLen = GetScrap(hContent, 'TEXT', &offset);
  1261.             HLock(hContent);
  1262.             TextBox(*hContent, scrapLen, &pWin->portRect, teFlushDefault);
  1263.             DisposeHandle(hContent);
  1264.         }
  1265.     }
  1266. }
  1267.  
  1268. // ------------------------------------------------------------------------
  1269. // TScrap::Put
  1270. // Put the contents of the handle into the scrap.
  1271. // The handle is not disposed.
  1272. //
  1273. void
  1274. TScrap::Put(Handle hToScrap)
  1275. {
  1276.     if(hToScrap)
  1277.     {
  1278.         HLock(hToScrap);
  1279.         (void) ZeroScrap();
  1280.         (void) PutScrap(GetHandleSize(hToScrap), 'TEXT', *hToScrap);
  1281.         HUnlock(hToScrap);
  1282.     }
  1283. }
  1284.  
  1285. // ------------------------------------------------------------------------
  1286. // TScrap::Update
  1287. // Set the value of the last scrapCount.
  1288. // Return true if it has changed.
  1289. Boolean
  1290. TScrap::Update()
  1291. {
  1292.     Boolean hasChanged=false;
  1293.     PScrapStuff pScrapStuff = InfoScrap();
  1294.     if(pScrapStuff)
  1295.     {
  1296.         hasChanged = (pScrapStuff->scrapCount!=this->fLastScrapCount);
  1297.         this->fLastScrapCount = pScrapStuff->scrapCount;
  1298.     }
  1299.     return hasChanged;
  1300. }
  1301.  
  1302.